package service

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io"
	"k8s-dash/dto"
	"k8s-dash/utils"
	"k8s-dash/utils/types"
	coreV1 "k8s.io/api/core/v1"
	metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/client-go/kubernetes/scheme"
	"k8s.io/client-go/tools/remotecommand"
	"net/http"
)

type pod struct{}

var Pod pod

type PodsResp struct {
	Total int          `json:"total"`
	Items []coreV1.Pod `json:"items"`
}
type PodsToNS struct {
	Namespace string `json:"namespaces"`
	PodNum    int    `json:"pod_num"`
}

// GetPodList 获取pod列表
func (p *pod) GetPodList(filterName, namespace string, limit, page int) (resp *PodsResp, err error) {
	podList, err := utils.K8sClient.K8sClient.CoreV1().Pods(namespace).List(context.TODO(), metaV1.ListOptions{})
	if err != nil {
		return nil, err
	}
	//清洗数据
	selectedData := &dataSelector{
		GenericDataList: p.toCells(podList.Items),
		DataSelectQuery: &DataSelectorQuery{
			Filter:   &FilterQuery{filterName},
			Paginate: &PageQuery{limit, page},
		},
	}
	//先过滤
	sd := selectedData.Filter()
	total := len(sd.GenericDataList)
	//排序
	data := sd.Sort().Paginate()
	//再将数据装换为corev1.pod
	pods := p.FromCells(data.GenericDataList)
	//返回数据
	return &PodsResp{
		Total: total,
		Items: pods,
	}, nil
}

// GetPodDetail 获取pod详情
func (p *pod) GetPodDetail(podName, namespace string) (*coreV1.Pod, error) {
	pod, err := utils.K8sClient.K8sClient.CoreV1().Pods(namespace).Get(context.TODO(), podName, metaV1.GetOptions{})
	if err != nil {
		return nil, err
	}
	return pod, nil
}

// DeletePod 删除Pod
func (p *pod) DeletePod(podName, namespace string) error {
	return utils.K8sClient.K8sClient.CoreV1().Pods(namespace).Delete(context.TODO(), podName, metaV1.DeleteOptions{})
}

// UpdatePod 更新pod
func (p *pod) UpdatePod(namespace, content string) error {
	var pod = &coreV1.Pod{}
	//将content反序列化为pod
	err := json.Unmarshal([]byte(content), pod)
	if err != nil {
		return err
	}
	if _, err := utils.K8sClient.K8sClient.CoreV1().Pods(namespace).Update(context.TODO(), pod, metaV1.UpdateOptions{}); err != nil {
		return err
	}
	return nil
}

// GetContainerName 获取容器的名字
func (p *pod) GetContainerName(podName, namespace string) (containers []string, err error) {
	podDetail, err := p.GetPodDetail(podName, namespace)
	if err != nil {
		return nil, err
	}
	for _, container := range podDetail.Spec.Containers {
		containers = append(containers, container.Name)
	}
	return containers, nil
}

// GetPodLog 获取容器日志
func (p *pod) GetPodLog(containerName, podName, namespace string) (log string, err error) {
	fmt.Println("containerName:", containerName)
	fmt.Println("podName:", podName)
	fmt.Println("namespace", namespace)
	//设置日志相关配置
	lineLimit := int64(200)
	op := &coreV1.PodLogOptions{
		Container: containerName,
		TailLines: &lineLimit,
	}
	//获取请求实例
	req := utils.K8sClient.K8sClient.CoreV1().Pods(namespace).GetLogs(podName, op)
	//发起stream连接，得到response.body
	podLogs, err := req.Stream(context.TODO())
	if err != nil {
		return "", err
	}
	//关闭stream
	defer func(podLogs io.ReadCloser) {
		err := podLogs.Close()
		if err != nil {
		}
	}(podLogs)
	//将获取的body写入缓冲区
	buf := new(bytes.Buffer)
	if _, err := io.Copy(buf, podLogs); err != nil {
		return "", err
	}
	return buf.String(), nil
}

// GetPodsToNS 获取对应namespace下pod的数量，这个功能跟podList功能重复，这个是获取所有ns分别对应的pod数量
func (p *pod) GetPodsToNS() (PNS []*PodsToNS, err error) {
	//首先获取所有的ns
	namespaceList, err := utils.K8sClient.K8sClient.CoreV1().Namespaces().List(context.TODO(), metaV1.ListOptions{})
	if err != nil {
		return nil, err
	}
	for _, namespace := range namespaceList.Items {
		podList, err := utils.K8sClient.K8sClient.CoreV1().Pods(namespace.Name).List(context.TODO(), metaV1.ListOptions{})
		if err != nil {
			return nil, err
		}
		//组装数据
		pns := &PodsToNS{
			Namespace: namespace.Name,
			PodNum:    len(podList.Items),
		}
		PNS = append(PNS, pns)
	}
	return PNS, nil
}

// 类型转换的方法 coreV1.pod => DataCell,DataCell => coreV1.pod
func (p *pod) toCells(pods []coreV1.Pod) []DataCell {
	cells := make([]DataCell, len(pods))
	for i := range pods {
		cells[i] = podCell(pods[i])
	}
	return cells
}

func (p *pod) FromCells(cells []DataCell) []coreV1.Pod {
	pods := make([]coreV1.Pod, len(cells))
	for i := range cells {
		pods[i] = coreV1.Pod(cells[i].(podCell))
	}
	return pods
}

func (p *pod) WebShellHandler(webShellOptions *dto.WebShellOptions, w http.ResponseWriter, r *http.Request) error {
	session, err := types.NewTerminalSession(w, r)
	if err != nil {
		return err
	}
	// 处理关闭
	defer func() {
		_ = session.Close()
	}()

	// 组装 POST 请求
	req := utils.K8sClient.K8sClient.CoreV1().RESTClient().Post().
		Resource("pods").
		Name(webShellOptions.Pod).
		Namespace(webShellOptions.Namespace).
		SubResource("exec").
		VersionedParams(&coreV1.PodExecOptions{
			Container: webShellOptions.Container,
			Command:   []string{"/bin/sh"},
			Stderr:    true,
			Stdin:     true,
			Stdout:    true,
			TTY:       true,
		}, scheme.ParameterCodec)

	// remotecommand 主要实现了http 转 SPDY 添加X-Stream-Protocol-Version相关header 并发送请求
	executor, err := remotecommand.NewSPDYExecutor(utils.K8sClient.Config, "POST", req.URL())
	if err != nil {
		return err
	}
	// 与 kubelet 建立 stream 连接
	if err = executor.Stream(remotecommand.StreamOptions{
		Stdout:            session,
		Stdin:             session,
		Stderr:            session,
		TerminalSizeQueue: session,
		Tty:               true,
	}); err != nil {
		_, _ = session.Write([]byte("exec pod command failed," + err.Error()))
		// 标记关闭terminal
		session.Done()
	}
	return nil
}
